package com.beta.listener;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.alibaba.fastjson.JSON;
import com.beta.em.order.OrderStatus;
import com.beta.entity.OrderItems;
import com.beta.entity.Orders;
import com.beta.event.order.OrderItemEvent;
import com.beta.event.order.OrderItemPayloadEvent;
import com.beta.event.order.OrderPayloadEvent;
import com.beta.service.*;
import com.beta.service.impl.PublishService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionalEventListener;

import java.util.List;

/**
 * Created by vector on 2016/12/7.
 */
@Component
public class OrderEventListener {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private IOrderItemsService orderItemsService;
    @Autowired
    private IOrderSettleQueuesService settledQueuesService;
    @Autowired
    private IPushToAppService pushToAppService;
    @Autowired
    private ICleanTxnDetailsService cleanTxnDetailsService;
    @Autowired
    private IUserBalancesService userBalancesService;

    @Autowired
    private PublishService publishService;

    @EventListener(condition = "T(com.beta.event.order.OrderEvent).CREATE.equals(#payloadEvent.event)")
    public void onCreate(OrderPayloadEvent payloadEvent) {
        Orders orders = payloadEvent.getPayload();
        logger.info("订单创建完成 ==> order - {}", JSON.toJSONString(orders));

    }

    @EventListener(condition = "T(com.beta.event.order.OrderEvent).CANCEL.equals(#payloadEvent.event)")
    public void onCancel(OrderPayloadEvent payloadEvent) {
        Orders orders = payloadEvent.getPayload();
        logger.info("订单取消 ==> order - {}", JSON.toJSONString(orders));
    }

    @EventListener(condition = "T(com.beta.event.order.OrderEvent).PAYMENT.equals(#payloadEvent.event)")
    public void onPayment(OrderPayloadEvent payloadEvent) {
//        logger.info("订单支付 ==> order - {}", JSON.toJSONString(payloadEvent.getPayload()));
    }

    @EventListener(condition = "T(com.beta.event.order.OrderEvent).PAYMENT_SUCCESS.equals(#payloadEvent.event)")
    public void onPaySuccess(OrderPayloadEvent payloadEvent) {
        Orders order = payloadEvent.getPayload();
        logger.info("订单支付完成 ==> order - {}", JSON.toJSONString(order));

        // 更新用户账户金额
        userBalancesService.updateBalanceOnPaySuccess(order);

        // 交易明细数据记录
        cleanTxnDetailsService.recordOrderPayment(order);
    }

    @EventListener(condition = "T(com.beta.event.order.OrderEvent).ASSIGNING.equals(#payloadEvent.event)")
    public void onAssigning(OrderPayloadEvent payloadEvent) {
//        logger.info("订单分发中 ==> 指定承运人");
        Orders order = payloadEvent.getPayload();

        // 记录订单项的分发
        cleanTxnDetailsService.recordOrderAssigning(order);
    }

    @EventListener(condition = "T(com.beta.event.order.OrderEvent).PICKING.equals(#payloadEvent.event)")
    public void onPicking(OrderPayloadEvent payloadEvent) {
        Orders order = payloadEvent.getPayload();
        logger.info("订单已接单 ==> order - {}", JSON.toJSONString(order));

        // 记录订单项的分发
        cleanTxnDetailsService.recordOrderPicking(order);
    }

    @EventListener(condition = "T(com.beta.event.order.OrderEvent).SHIPPING.equals(#payloadEvent.event)")
    public void onShipping(OrderPayloadEvent payloadEvent) {
        Orders order = payloadEvent.getPayload();
        logger.info("订单已发货 ==> order - {}", JSON.toJSONString(order));

        // 消息推送
        pushToAppService.pushToSingle(order.getUserId(), "您的订单已发货", OrderStatus.DELIVERING.getValue());

        // 记录订单项的分发
        cleanTxnDetailsService.recordOrderShipping(order);
    }

    @EventListener(condition = "T(com.beta.event.order.OrderEvent).RECEIPT_CONFIRMED.equals(#payloadEvent.event)")
    public void onReceived(OrderPayloadEvent payloadEvent) {
        Orders order = payloadEvent.getPayload();
        logger.info("订单已收货 ==> order - {}", JSON.toJSONString(order));

        // 记录订单项的流水
        cleanTxnDetailsService.recordOrderReceived(order);
    }

    @Order(Ordered.HIGHEST_PRECEDENCE)
    @EventListener(condition = "T(com.beta.event.order.OrderEvent).COMPLETED.equals(#payloadEvent.event)")
    public void onCompleted(OrderPayloadEvent payloadEvent) {
        Orders order = payloadEvent.getPayload();
        logger.info("订单已完成 ==> order - {}", JSON.toJSONString(order));

        // 更新用户账户
        userBalancesService.updateBalanceOnCompleted(order);
        // 创建订单结算队列
        settledQueuesService.createSettleQueues(order);
    }

    // 订单完成事务提交后才执行分账，分账如果报错不影响主事务（失败的结算任务由定时任务补偿）
    @Order(Ordered.LOWEST_PRECEDENCE)
    @TransactionalEventListener(condition = "T(com.beta.event.order.OrderEvent).COMPLETED.equals(#payloadEvent.event)")
    public void attemptToSettle(OrderPayloadEvent payloadEvent) {
        Orders order = payloadEvent.getPayload();
        logger.info("尝试结算订单 ==> order - {}", JSON.toJSONString(order));

        // 执行结算
        settledQueuesService.executeSettleOrder(order.getId());
    }

    @EventListener(condition = "T(com.beta.event.order.OrderEvent).SETTLED.equals(#payloadEvent.event)")
    public void onSettled(OrderPayloadEvent payloadEvent) {
        Orders order = payloadEvent.getPayload();
        logger.info("订单结算完成 ==> order - {}", JSON.toJSONString(order));

        // 删除结算队列
        settledQueuesService.deleteSettleQueue(order.getId());

        // 结算成功时更新用户账户
        userBalancesService.updateBalanceOnSettled(order);

        // 记录订单详情流水
        cleanTxnDetailsService.recordOrderSettled(order);

        // 发布订单项退款成功事件
        List<OrderItems> refundAgreeItems = orderItemsService.getRefundAgreeItems(order.getId());
        if (CollectionUtils.isNotEmpty(refundAgreeItems)) {
            refundAgreeItems.forEach(refundAgreeItem -> {
                publishService.publishApplicationEvent(new OrderItemPayloadEvent(OrderItemEvent.REFUND_SETTLED, refundAgreeItem));
            });
        }
    }

}